package com.rongji.dfish.demo.editor.service.uiadaptor;

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import com.rongji.dfish.base.Utils;
import com.rongji.dfish.base.util.BeanUtil;
import com.rongji.dfish.framework.FrameworkHelper;
import com.rongji.dfish.ui.form.Checkboxgroup;

/**
 * ComponentTypeAdaptor为普通组件的类型适配器
 * <p>一般一个普通组件可以通过类反射的方式获取它的类型适配器。而不需要去编写众多适配器
 * 并且编写的适配器维护可能还是一个麻烦的事情。</p>
 * @author DFish Team
 * @version 1.0.20160815
 */
public class ComponentTypeAdaptor extends TypeAdaptor {
	private Class<?> clz;
	private List<PropertyDefine> defineProps;
	/**
	 * 取得组件原型Class
	 * @return Class
	 */
	public Class<?> getClz(){
		return clz;
	}

	/**
	 * 构造函数
	 * @param clz 组件原型Class
	 */
	public ComponentTypeAdaptor(Class<?> clz) {
		this.clz = clz;
		typeName = BeanUtil.getClassShortName(clz.getName());
	}
	public List<PropertyDefine> getDefineProps() {
		if (defineProps == null) {
			defineProps = ComponentInfo.loadPropDefine(clz);
		}
		return defineProps;
	}





	@SuppressWarnings("rawtypes")
	public Object newInstance(ComponentData data, Object parent) {
		Map<Constructor, List<String>> cons = BeanExtUtil.getInstance().getAllConstructorParameters(clz);
		if(cons==null||cons.size()==0){
			return null; //该方法不让实例化
		}
		Map.Entry<Constructor, List<String>> con = findBestConstructor(cons, data.getProps());
		return newInstance(con.getKey(), con.getValue(), data, true);
	}

	@SuppressWarnings("rawtypes")
	private Map.Entry<Constructor, List<String>> findBestConstructor(Map<Constructor, List<String>> cons, Map<String, String> props) {
		List<Map.Entry<Constructor, List<String>>> consList = new ArrayList<Map.Entry<Constructor, List<String>>>(cons.entrySet());
		//尝试移除非简单类型的构造器，因为代码生成器并不懂如何生成他们
		for(Iterator<Map.Entry<Constructor, List<String>>> iter=consList.iterator();iter.hasNext();){
			Map.Entry<Constructor, List<String>> item=iter.next();
			if(hasComplexArgument(item.getKey())){
				iter.remove();
			}
		}
		Collections.sort(consList, new Comparator<Map.Entry<Constructor, List<String>>>() {
			@Override
			public int compare(Entry<Constructor, List<String>> o1, Entry<Constructor, List<String>> o2) {
				int l1 = o1.getValue() == null ? 0 : o1.getValue().size();
				int l2 = o2.getValue() == null ? 0 : o2.getValue().size();
				return l2 - l1;
			}
		});
		for (Map.Entry<Constructor, List<String>> con : consList) {
			// 都不为空的属性则选择较长的那个,否则选择最短的那个。
			boolean suit = true;
			if(con.getValue()!=null){
				for (String argName : con.getValue()) {
					if (props==null||!props.containsKey(argName)) {
						suit = false;
					}
				}
			}
			if (suit) {
				return con;
			}
		}
		Map.Entry<Constructor, List<String>> con = consList.get(consList.size() - 1);
		return con;
	}
	private static HashSet<Class<?>> SIMPLE_TYPES=new HashSet<Class<?>>();
	static{
		SIMPLE_TYPES.add(Object.class);
		SIMPLE_TYPES.add(String.class);
		SIMPLE_TYPES.add(java.util.Date.class);
		SIMPLE_TYPES.add(Number.class);
		SIMPLE_TYPES.add(List.class);
		SIMPLE_TYPES.add(Collection.class);
		SIMPLE_TYPES.add(int.class);
		SIMPLE_TYPES.add(Integer.class);
		SIMPLE_TYPES.add(boolean.class);
		SIMPLE_TYPES.add(Boolean.class);
		SIMPLE_TYPES.add(long.class);
		SIMPLE_TYPES.add(Long.class);
		SIMPLE_TYPES.add(char.class);
		SIMPLE_TYPES.add(Character.class);
		SIMPLE_TYPES.add(float.class);
		SIMPLE_TYPES.add(Float.class);
		SIMPLE_TYPES.add(Short.class);
		SIMPLE_TYPES.add(Character.class);
		SIMPLE_TYPES.add(byte.class);
		SIMPLE_TYPES.add(Byte.class);
	}
	private boolean hasComplexArgument(Constructor<?> c) {
		for(Class<?> clz:c.getParameterTypes()){
			if(!SIMPLE_TYPES.contains(clz)){
				return true;
			}
		}
		return false;
	}

	@SuppressWarnings("rawtypes")
	private Object newInstance(Constructor con, List<String> argNames, ComponentData data, boolean removeProp) {
		if(argNames==null){
			try {
				return con.newInstance();
			} catch (Exception e) {
				FrameworkHelper.LOG.error(null, e);
			}
		}
		Map<String, String> props = data.getProps();
		List<Object> args = new ArrayList<Object>(argNames.size());
		int i = 0;
		for (String argName : argNames) {
			String argStr = getProperty(props, argName, removeProp);
			//FORM部分支持valueObject的设置，但是CheckBox特殊它默认是Object[]
			if("value".equals(argName)&&con.getDeclaringClass()==Checkboxgroup.class){
				args.add(ViewBuilder.toArg(argStr, Object[].class));
				i++;
			}else{
				args.add(ViewBuilder.toArg(argStr, con.getParameterTypes()[i++]));
			}
		}
		try {
			return con.newInstance(args.toArray());
		} catch (Exception e) {
			FrameworkHelper.LOG.error(null, e);
		}
		return null;
	}
	


	@SuppressWarnings("rawtypes")
	public void getInstanceCode(StringBuilder javaCode, ComponentData data,String variable) {
//		String code = "";
		String type = getTypeName();
		// 实例化代码
    	if (Utils.notEmpty(variable)) {
    		javaCode.append(type).append(' ' ).append(variable ).append(" = ");
    	}
    	Map<Constructor, List<String>> cons = BeanExtUtil.getInstance().getAllConstructorParameters(clz);
		Map.Entry<Constructor, List<String>> con = findBestConstructor(cons, data.getProps());
    	javaCode.append("new ").append(type).append('(' );
    	Map<String, String> props = data.getProps();
		int i = 0;
		for (String argName : con.getValue()) {
			String argStr = getProperty(props, argName, true);
			if (i > 0) {
				javaCode.append(", ");
			}
			JavaCodeBuilder.toArg(javaCode, type, con.getKey().getParameterTypes()[i++], argName, argStr);
		}
    	javaCode.append(")");
    	// 初始化实例
    	JavaCodeBuilder.buildInstanceWithProps(javaCode,data,this);
	}
	



	



	/**
     * 获取属性值
     * @param props 属性名称-值映射
     * @param key 属性名称
     * @param removeProp 获取属性值后是否将此属性值从映射中移除
     * @return String
     */
    protected String getProperty(Map<String, String> props, String key, boolean removeProp) {
    	// 将这个构造函数中的属性移除,不需要再set
    	if(props == null){
    		return "";
    	}
    	String value = removeProp ? props.remove(key) : props.get(key);
    	if (value == null) {
    		value = "";
    	}
    	return value;
    }

}
